var nativeToString = Object.prototype.toString;
var nativeHasOwnProperty = Object.prototype.hasOwnProperty;

function isEventType(eventBo, type, definition) {

    var isType = eventBo.$instanceOf(type);
    var isDefinition = false;

    var definitions = eventBo.eventDefinitions || [];
    forEach(definitions, function(def) {
        if (def.$type === definition) {
            isDefinition = true;
        }
    });

    return isType && isDefinition;
}

function isEventSubProcess(element) {
    return element && !!getBusinessObject(element).triggeredByEvent;
}

function assign(target) {
    for (var _len = arguments.length, others = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
        others[_key - 1] = arguments[_key];
    }

    return _extends.apply(void 0, [target].concat(others));
}

function bind$2(fn, target) {
    return fn.bind(target);
}

function _extends() {
    _extends = Object.assign || function (target) {
        for (var i = 1; i < arguments.length; i++) {
            var source = arguments[i];

            for (var key in source) {
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                    target[key] = source[key];
                }
            }
        }

        return target;
    };

    return _extends.apply(this, arguments);
}

function flatten(arr) {
    return Array.prototype.concat.apply([], arr);
}


function isUndefined$1(obj) {
    return obj === undefined;
}
function isDefined(obj) {
    return obj !== undefined;
}
function isNil(obj) {
    return obj == null;
}
function isArray$2(obj) {
    return nativeToString.call(obj) === '[object Array]';
}
function isObject(obj) {
    return nativeToString.call(obj) === '[object Object]';
}
function isNumber(obj) {
    return nativeToString.call(obj) === '[object Number]';
}
function isFunction(obj) {
    var tag = nativeToString.call(obj);
    return tag === '[object Function]' || tag === '[object AsyncFunction]' || tag === '[object GeneratorFunction]' || tag === '[object AsyncGeneratorFunction]' || tag === '[object Proxy]';
}
function isString(obj) {
    return nativeToString.call(obj) === '[object String]';
}

function isAny(element, types) {
    return some(types, function(t) {
        return is$1(element, t);
    });
}

function is$1(element, type) {
    var bo = getBusinessObject(element);

    return bo && (typeof bo.$instanceOf === 'function') && bo.$instanceOf(type);
}

function getBusinessObject(element) {
    return (element && element.businessObject) || element;
}

function some(collection, matcher) {
    return !!find(collection, matcher);
}

function find(collection, matcher) {
    matcher = toMatcher(matcher);
    var match;
    forEach(collection, function (val, key) {
        if (matcher(val, key)) {
            match = val;
            return false;
        }
    });
    return match;
}

function forEach(collection, iterator) {
    var val, result;

    if (isUndefined$1(collection)) {
        return;
    }

    var convertKey = isArray$2(collection) ? toNum : identity;

    for (var key in collection) {
        if (has(collection, key)) {
            val = collection[key];
            result = iterator(val, convertKey(key));

            if (result === false) {
                return val;
            }
        }
    }
}

function has(target, key) {
    return nativeHasOwnProperty.call(target, key);
}

function matchPattern(pattern) {
    return function (el) {
        return every(pattern, function (val, key) {
            return el[key] === val;
        });
    };
}

function toExtractor(extractor) {
    return isFunction(extractor) ? extractor : function (e) {
        return e[extractor];
    };
}

function toMatcher(matcher) {
    return isFunction(matcher) ? matcher : function (e) {
        return e === matcher;
    };
}

function identity(arg) {
    return arg;
}

function toNum(arg) {
    return Number(arg);
}

function hasPrimaryModifier(event) {
    var originalEvent = getOriginal$1(event) || event;

    if (!isPrimaryButton(event)) {
        return false;
    }

    // Use cmd as primary modifier key for mac OS
    if (isMac()) {
        return originalEvent.metaKey;
    } else {
        return originalEvent.ctrlKey;
    }
}


function isButton(event, button) {
    return (getOriginal$1(event) || event).button === button;
}

function isPrimaryButton(event) {

    // button === 0 -> left áka primary mouse button
    return isButton(event, 0);
}

function isAuxiliaryButton(event) {

    // button === 1 -> auxiliary áka wheel button
    return isButton(event, 1);
}

function isMac() {
    return (/mac/i).test(navigator.platform);
}

function getOriginal$1(event) {
    return event.originalEvent || event.srcEvent;
}

function isExpanded(element) {

    if (is$1(element, 'bpmn:CallActivity')) {
        return false;
    }

    if (is$1(element, 'bpmn:SubProcess')) {
        return getBusinessObject(element).di && !!getBusinessObject(element).di.isExpanded;
    }

    if (is$1(element, 'bpmn:Participant')) {
        return !!getBusinessObject(element).processRef;
    }

    return true;
}

function isInterrupting(element) {
    return element && getBusinessObject(element).isInterrupting !== false;
}

function isEventSubProcess(element) {
    return element && !!getBusinessObject(element).triggeredByEvent;
}

function hasEventDefinition$2(element, eventType) {
    var bo = getBusinessObject(element),
        hasEventDefinition = false;

    if (bo.eventDefinitions) {
        forEach(bo.eventDefinitions, function(event) {
            if (is$1(event, eventType)) {
                hasEventDefinition = true;
            }
        });
    }

    return hasEventDefinition;
}

function hasErrorEventDefinition(element) {
    return hasEventDefinition$2(element, 'bpmn:ErrorEventDefinition');
}

function hasEscalationEventDefinition(element) {
    return hasEventDefinition$2(element, 'bpmn:EscalationEventDefinition');
}

function hasCompensateEventDefinition(element) {
    return hasEventDefinition$2(element, 'bpmn:CompensateEventDefinition');
}

/**
 * Collect all lane shapes in the given paren
 *
 * @param  {djs.model.Shape} shape
 * @param  {Array<djs.model.Base>} [collectedShapes]
 *
 * @return {Array<djs.model.Base>}
 */
function collectLanes(shape, collectedShapes) {

    collectedShapes = collectedShapes || [];

    shape.children.filter(function(s) {
        if (is$1(s, 'bpmn:Lane')) {
            collectLanes(s, collectedShapes);

            collectedShapes.push(s);
        }
    });

    return collectedShapes;
}


/**
 * Return the lane children of the given element.
 *
 * @param {djs.model.Shape} shape
 *
 * @return {Array<djs.model.Shape>}
 */
function getChildLanes(shape) {
    return shape.children.filter(function(c) {
        return is$1(c, 'bpmn:Lane');
    });
}


var LANE_PARENTS = [
    'bpmn:Participant',
    'bpmn:Process',
    'bpmn:SubProcess'
];

/**
 * Return the root element containing the given lane shape
 *
 * @param {djs.model.Shape} shape
 *
 * @return {djs.model.Shape}
 */
function getLanesRoot(shape) {
    return getParent(shape, LANE_PARENTS) || shape;
}

function getParent(element, type) {
    if (!type) {
        return element.$parent;
    }

    if (is(element, type)) {
        return element;
    }

    if (!element.$parent) {
        return;
    }

    return getParent(element.$parent, type);
}
